from django.http import HttpResponse
import urllib
import urllib2
from urllib2 import URLError
from httplib import BadStatusLine
import json
import re
import util
import uuid
import unicodedata
from socket import timeout
from datetime import date
import time
from api.models import Author, Price, Book, Query
from django.db import IntegrityError
import os
from main.chmng import CheevoManager
'''
Created on Apr 4, 2011

@author: Miles
'''

NAMESPACE_COLLECTOR = 'mt.api.collector'

mandatory_fields = [['author'],
                    ['title'],
                    ['isbn_10', 'isbn_13'],
                    ['price_new', 'price_used', 'price_market'],
                    ['purchase_url'],]
                    #['description']]

item_fields = ['author', 'title',
          'isbn_10', 'isbn_13',
          'price',
          'description',
          'image_url'
          ]

price_fields = ['price_new', 'price_used', 'price_market',
               'purchase_url']

symbols = ['"*', '[...]', '</?\w+\s+[^>]*>']

def search(request):
    try:
        args = dict(request.GET.items())


    except AttributeError:
        args = dict(request)

    opts = {'indent': None, 'max': 0, 'offset': 0}
    for o in ['indent', 'max', 'offset']:
        if o in args:
            opts[o] = int(args[o])
            del args[o]

    if 'user' in request and request.user.get_profile().pk:
        user_id = request.user.get_profile().pk
    else:
        user_id = -1

    logquery(args, user_id)

    extParams = urllib.urlencode({"action":"retrieve"})


    extSock = urllib2.urlopen("http://teamvilot.com/?%s" % (extParams))

    extractors = json.loads(extSock.read())

    isbnmap = {}

    for extractor in extractors:
        try:
            sock = urllib2.urlopen(extractor['api_url'] + "?%s" % urllib.urlencode(args),timeout=10)
            results = json.loads(sock.read())

        except URLError:
            results = None
        except ValueError:
            results = None
        except timeout:
            results = None

        print(extractor['name'])

        if results:
            for result in results:
                formatted = {}
                rfields = result['attributes']

                if (checkMandatoryFields(rfields) and checkIsbns(rfields)):
                    isbn = getIsbn(rfields)

                    if isbn is not None:
                        if isbn in isbnmap:
                            formatted = isbnmap[isbn]
                            prices = convertPrices(getFields(rfields, price_fields), extractor['name'])
                            allprices = formatted['prices']
                            for price in prices:
                                insertPrice(price, allprices)
                                #formatted['prices'].append(price)

                            formatted['prices'] = allprices

                            if 'isbn_10' not in formatted and 'isbn_10' in rfields:
                                formatted['isbn_10'] = rfields['isbn_10']

                            if 'description' in formatted:
                                formatted['description'] = remove_symbols(formatted['description'])
                            if 'description' not in formatted and 'description' in rfields:
                                formatted['description'] = remove_symbols(rfields['description'])

                            isbnmap[isbn] = formatted
                        else:
                            formatted = getFields(rfields, item_fields)
                            prices = convertPrices(getFields(rfields, price_fields), extractor['name'])
                            formatted['isbn_13'] = isbn
                            formatted['prices'] = []
                            allprices = []
                            for price in prices:
                                #formatted['prices'].append(price)
                                insertPrice(price, allprices)

                            formatted['prices'] = allprices

                            formatted['uuid'] = int(str(uuid.uuid3(uuid.NAMESPACE_X500, str(isbn)).int)[:16])

                            isbnmap.update({isbn : formatted})

    results = isbnmap.values()

    insertResults(results)
    #return json.dumps(results, indent=opts['indent'])
    return HttpResponse(json.dumps(results, indent=opts['indent']), mimetype='application/json')

def search2(request):
    try:
        args = dict(request.GET.items())


    except AttributeError:
        args = dict(request)

    opts = {'indent': None, 'max': 0, 'offset': 0}
    for o in ['indent', 'max', 'offset']:
        if o in args:
            opts[o] = int(args[o])
            del args[o]

    if 'user' in request and request.user:
        user_id = request.user
    else:
        user_id = None

    logquery(args, user_id)

    extParams = urllib.urlencode({"action":"retrieve"})

    extSock = urllib2.urlopen("http://teamvilot.com/?%s" % (extParams))

    extractors = json.loads(extSock.read())

    isbnmap = {}

    for extractor in extractors:
        try:
            sock = urllib2.urlopen(extractor['api_url'] + "?%s" % urllib.urlencode(args),timeout=10)
            results = json.loads(sock.read())

        except URLError:
            results = None
        except ValueError:
            results = None
        except timeout:
            results = None
        except BadStatusLine:
            results = None

        print(extractor['name'])

        if results:
            if isinstance(results, dict):
                print results
                
                list = []
                list.append(results)
                results = list
                
                print results
                
            i = 0
            
            for result in results:
                formatted = {}
                
                rfields = result['attributes']

                if (checkMandatoryFields(rfields) and checkIsbns(rfields)):
                    isbn = getIsbn(rfields)

                    if isbn is not None:
                        if isbn in isbnmap:
                            formatted = isbnmap[isbn]
                            prices = convertPrices(getFields(rfields, price_fields), extractor['name'])
                            allprices = formatted['prices']
                            
                            for price in prices:
                                insertPrice(price, allprices)

                            formatted['prices'] = allprices

                            if 'isbn_10' not in formatted and 'isbn_10' in rfields:
                                formatted['isbn_10'] = rfields['isbn_10']

                            if 'description' in formatted:
                                formatted['description'] = remove_symbols(remove_html_tags(formatted['description']))
                            if 'description' not in formatted and 'description' in rfields:
                                formatted['description'] = remove_symbols(remove_html_tags(rfields['description']))

                            isbnmap[isbn] = formatted
                        else:
                            formatted = getFields(rfields, item_fields)
                            prices = convertPrices(getFields(rfields, price_fields), extractor['name'])
                            formatted['isbn_13'] = isbn
                            formatted['prices'] = []
                            allprices = []
                            for price in prices:
                                insertPrice(price, allprices)

                            formatted['prices'] = allprices

                            formatted['uuid'] = int(str(uuid.uuid3(uuid.NAMESPACE_X500, str(isbn)).int)[:16])
                            
                            formatted['item_num'] = i
                            
                            i = i + 1
                            
                            isbnmap.update({isbn : formatted})

    results = isbnmap.values()

    insertResults(results)

    return json.dumps(results, indent=opts['indent'])

def checkMandatoryFields(fields):
    valid = True
    for field in mandatory_fields:
        sub_valid = False

        for subfield in field:
            sub_valid = sub_valid or (subfield in fields and fields[subfield])

        valid = valid and sub_valid

    return valid

def getFields(fields, item_set):
    return dict((k, v) for k, v in fields.items() if k in item_set)

def insertPrice(price, prices):
    if prices and len(prices) > 0:
        for i in range(len(prices)):
            if float(price['price']) < float(prices[i]['price']):
                prices.insert(i, price)
                
        prices.append(price)
        
        return prices
    else:
        prices.append(price)
        return prices

def convertPrices(price, vendor):
    prices = []
    if 'price_new' in price and price['price_new'] != '':
        prices.append({'condition' : 'new',
         'price' : price['price_new'],
         'purchase_url' : price['purchase_url'],
         'vendor' : vendor,
         'updated' : '00000'})
    if 'price_used' in price and price['price_used'] != '':
        prices.append({'condition' : 'used',
         'price' : price['price_used'],
         'purchase_url' : price['purchase_url'],
         'vendor' : vendor,
         'updated' : '00000'})
    if 'price_market' in price and price['price_market'] != '':
        prices.append({'condition' : 'market',
         'price' : price['price_market'],
         'purchase_url' : price['purchase_url'],
         'vendor' : vendor,
         'updated' : '00000'})

    return prices

def checkUnicode(string):
    if re.search('\u', string):
        return 1
    else:
        return 0

def checkIsbns(fields):
    if 'isbn_10' in fields and fields['isbn_10'] is not None:
        isbn_10 = fields['isbn_10'].strip()
        try:
            int(isbn_10)

        except ValueError:
            return False

        return util.valid_isbn_13(util.isbn_10_13(isbn_10))
    elif 'isbn_13' in fields and fields['isbn_13'] is not None:
        isbn_13 = fields['isbn_13'].strip()
        try:
            int(isbn_13)

        except ValueError:
            return False

        if len(isbn_13) == 10:
            return util.valid_isbn_13(util.isbn_10_13(isbn_13))
        elif len(isbn_13) == 13:
            return util.valid_isbn_13(isbn_13)
    else:
        return False

def getIsbn(fields):
    if 'isbn_10' in fields and fields['isbn_10'] is not None:
        return (util.isbn_10_13(fields['isbn_10'].strip()))
    elif 'isbn_13' in fields and fields['isbn_13'] is not None:
        if len(fields['isbn_13'].strip()) == 10:
            return util.isbn_10_13(fields['isbn_13'].strip())
        elif len(fields['isbn_13'].strip()) == 13:
            return (fields['isbn_13']).strip()
    else:
        return None

def insertResults(results):
    for result in results:
        desc = ''
        img_url = ''

        if 'description' in result:
            desc = result['description']
        if 'image_url' in result:
            img_url = result['image_url']
        try:
            b = Book.objects.create(uuid=result['uuid'], title=result['title'],
                             isbn_13=result['isbn_13'], description=desc, image_url=img_url)

            b.save()
        except IntegrityError:
            b = Book(uuid=result['uuid'])

        for price in result['prices']:
            price_id = int(str(uuid.uuid3(uuid.NAMESPACE_X500, str(price['purchase_url']) + str(price['price'])).int)[:16])
            
            try:
                price_value = round(float(str(price['price'])), 2)
                
                p = Price.objects.create(pid=price_id,book=b,price=price_value,
                    purchase_url=str(price['purchase_url']), condition=price['condition'],
                    vendor=price['vendor'])

                p.save()
            except IntegrityError:
                None

        if 'author' in result:
            for authors in result['author']:
                try:
                    
                    try:
                        author = str(authors)
                    except UnicodeEncodeError:
                        author = 'Unknown'
                
                    a_id = uuid.uuid3(uuid.NAMESPACE_X500, author + str(b.uuid)).int

                    a_id = int(str(uuid.uuid3(uuid.NAMESPACE_X500, author + str(b.uuid)).int))
                    a = Author.objects.create(aid=a_id,book=b,author=authors)
                    a.save()

                except IntegrityError:
                    None

def getResults(query):
    b = Book(title=query)

def remove_symbols(data):
    str = data
    for symbol in symbols:
        p = re.compile(symbol)
        str = p.sub('', str)

    return str

def remove_html_tags(data):
    data = urllib.unquote(data)
    return re.sub(r'\<.*?\>', '', data)

def logquery(args, user_id):
    q = ''
    if 'string' in args:
        q = args['string']
    elif 'q' in args:
        q = args['q']
    elif 'isbn' in args:
        q = args['isbn']

    searches = Query.objects.filter(uid__exact=user_id).count()

    if user_id:
        if searches == 1:
            CheevoManager.grantCheevo(CheevoManager.firstblood, user_id)
        

    Query.objects.create(query=q, time=date.fromtimestamp(time.time()), uid=user_id)
